/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.common.base.service.impl;

import com.google.common.base.Strings;
import com.je.common.base.DynaBean;
import com.je.common.base.constants.tree.NodeType;
import com.je.common.base.exception.PlatformException;
import com.je.common.base.exception.PlatformExceptionEnum;
import com.je.common.base.service.CommonService;
import com.je.common.base.service.CommonTreeService;
import com.je.common.base.service.MetaService;
import com.je.common.base.service.rpc.BeanService;
import com.je.common.base.util.JEUUID;
import com.je.common.base.util.StringUtil;
import com.je.core.entity.extjs.JSONTreeNode;
import com.je.ibatis.extension.conditions.ConditionsWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

@Service
public class CommonTreeServiceImpl implements CommonTreeService {

    @Autowired
    private MetaService metaService;
    @Autowired
    private CommonService commonService;
    @Autowired
    private BeanService beanService;

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public DynaBean doSingleSave(String funcCode, DynaBean dynaBean, String codeGenFieldInfo, String batchFilesFields, String uploadableFields) {
        String tableCode = dynaBean.getTableCode();
        if (StringUtil.isEmpty(dynaBean.getStr("SY_STATUS"))) {
            //默认为启用数据
            dynaBean.set("SY_STATUS", "1");
        }

        if (StringUtil.isNotEmpty(codeGenFieldInfo)) {
            this.commonService.buildCode(codeGenFieldInfo, dynaBean);
        }

        //当前树形功能数据处理
        DynaBean parentBean = metaService.selectOneByPk(tableCode, dynaBean.getStr("SY_PARENT"), dynaBean.getPkCode() + ",SY_PATH,SY_NODETYPE,SY_TREEORDERINDEX,SY_LAYER");
        String mainId = JEUUID.uuid();
        dynaBean.setStr(dynaBean.getPkCode(), mainId);
        dynaBean.set("SY_PARENT", parentBean.getStr(dynaBean.getPkCode()));
        dynaBean.set("SY_PARENTPATH", parentBean.getStr("SY_PATH"));
        dynaBean.set("SY_PATH", parentBean.getStr("SY_PATH") + "/" + mainId);
        dynaBean.set("SY_NODETYPE", NodeType.LEAF);
        //dynaBean.set("SY_TREEORDERINDEX", generateTreeOrderIndex(tableCode, parentBean.getStr(dynaBean.getPkCode()), parentBean.getStr("SY_TREEORDERINDEX")));
        dynaBean.set("SY_LAYER", parentBean.getInt("SY_LAYER") + 1);
        commonService.generateTreeOrderIndex(dynaBean);
        commonService.buildModelCreateInfo(dynaBean);
        metaService.insert(dynaBean);
        commonService.doSaveFileMetadata(dynaBean, batchFilesFields, uploadableFields, funcCode);
        //检测子功能是否增加ROOT节点 (子功能多树)
        commonService.doChildrenTree(dynaBean, funcCode);

        //如节点不是根节点，则执行更新父节点类型
        if (!"ROOT".equals(parentBean.getStr(dynaBean.getPkCode()))) {
            parentBean.set("SY_NODETYPE", NodeType.GENERAL);
            metaService.update(parentBean);
        }

        return dynaBean;
    }

    @Override
    public DynaBean doMoreRootSave(String funcCode, DynaBean dynaBean, String codeGenFieldInfo, String batchFilesFields, String uploadableFields) {
        String tableCode = dynaBean.getTableCode();
        if (StringUtil.isEmpty(dynaBean.getStr("SY_STATUS"))) {
            //默认为启用数据
            dynaBean.set("SY_STATUS", "1");
        }
        if (StringUtil.isNotEmpty(codeGenFieldInfo)) {
            this.commonService.buildCode(codeGenFieldInfo, dynaBean);
        }

        //当前树形功能数据处理
        DynaBean parentBean = metaService.selectOneByPk(tableCode, dynaBean.getStr("SY_PARENT"), dynaBean.getPkCode() + ",SY_PATH,SY_NODETYPE,SY_TREEORDERINDEX,SY_LAYER");

        if (parentBean == null || NodeType.ROOT.equals(parentBean.getStr("SY_NODETYPE"))) {
            String childForeignField = commonService.findSubFuncForeignField(funcCode);
            parentBean = metaService.selectOne(tableCode, ConditionsWrapper.builder().eq(childForeignField, dynaBean.getStr(childForeignField)).eq("SY_NODETYPE", "ROOT"));
            if (parentBean == null) {
                //添加多根树根节点
                parentBean = commonService.addFuncMoreRootNode(funcCode, dynaBean);
            }
        } else {
            //如果上级不是root节点，在父节点下添加节点的时候要把父节点类型改为GENERAL
            parentBean.setStr("SY_NODETYPE", NodeType.GENERAL);
            metaService.update(parentBean);
        }

        String mainId = JEUUID.uuid();
        dynaBean.setStr(dynaBean.getPkCode(), mainId);
        dynaBean.set("SY_PARENT", parentBean.getStr(dynaBean.getPkCode()));
        dynaBean.set("SY_PARENTPATH", parentBean.getStr("SY_PATH"));
        dynaBean.set("SY_PATH", parentBean.getStr("SY_PATH") + "/" + mainId);
        dynaBean.set("SY_NODETYPE", NodeType.LEAF);
        //dynaBean.set("SY_TREEORDERINDEX", generateTreeOrderIndex(tableCode, parentBean.getStr(dynaBean.getPkCode()), parentBean.getStr("SY_TREEORDERINDEX")));
        dynaBean.set("SY_LAYER", parentBean.getInt("SY_LAYER") + 1);
        commonService.generateTreeOrderIndex(dynaBean);
        commonService.buildModelCreateInfo(dynaBean);
        metaService.insert(dynaBean);
        commonService.doSaveFileMetadata(dynaBean, batchFilesFields, uploadableFields, funcCode);

        return dynaBean;
    }

    @Override
    public JSONTreeNode buildSingleTreeNode(DynaBean dynaBean) {
        DynaBean table = beanService.getResourceTable(dynaBean.getTableCode());
        //构建树形模版
        JSONTreeNode template = beanService.buildJSONTreeNodeTemplate((List<DynaBean>) table.get(BeanService.KEY_TABLE_COLUMNS));
        JSONTreeNode node = new JSONTreeNode();
        node.setId(dynaBean.getStr(dynaBean.getPkCode()));
        //名称
        node.setText((String) dynaBean.get(template.getText()));
        //编码
        node.setCode((String) dynaBean.get(template.getCode()));
        //父节点
        node.setParent((String) dynaBean.get(template.getParent()));
        //节点信息
        if (StringUtil.isNotEmpty(template.getNodeInfo())) {
            node.setNodeInfo(StringUtil.getClobValue(dynaBean.get(template.getNodeInfo())));
        }
        //节点信息类型
        if (StringUtil.isNotEmpty(template.getNodeInfoType())) {
            node.setNodeInfoType(dynaBean.get(template.getNodeInfoType()) + "");
        }
        //是否叶子
        if (StringUtil.isNotEmpty(template.getNodeType())) {
            node.setLeaf(NodeType.LEAF.equalsIgnoreCase(dynaBean.get(template.getNodeType()) + ""));
            node.setNodeType(dynaBean.get(template.getNodeType()) + "");
        }
        if (StringUtil.isNotEmpty(template.getLayer())) {
            node.setLayer(dynaBean.get(template.getLayer()) + "");
        }
        //图标图片地址
        if (StringUtil.isNotEmpty(template.getIcon())) {
            node.setIcon(dynaBean.get(template.getIcon()) + "");
        }
        //图标样式
        if (StringUtil.isNotEmpty(template.getIconColor())) {
            node.setIconColor(dynaBean.get(template.getIconColor()) + "");
        }
        //是否禁用
        if (StringUtil.isNotEmpty(template.getDisabled())) {
            node.setDisabled(dynaBean.get(template.getDisabled()) + "");
        } else {
            node.setDisabled("0");
        }
        //树形路径
        if (StringUtil.isNotEmpty(template.getNodePath())) {
            node.setNodePath(dynaBean.get(template.getNodePath()) + "");
        }
        //描述
        if (StringUtil.isNotEmpty(template.getDescription())) {
            node.setDescription(StringUtil.getClobValue(dynaBean.get(template.getDescription())));
        }
        //排序
        if (StringUtil.isNotEmpty(template.getOrderIndex())) {
            node.setOrderIndex(dynaBean.get(template.getOrderIndex()) + "");
        }
        if (StringUtil.isNotEmpty(template.getTreeOrderIndex())) {
            node.setTreeOrderIndex(dynaBean.get(template.getTreeOrderIndex()) + "");
        }
        return node;
    }

    private String generateTreeOrderIndex(String tableCode, String parentId, String parentTreeOrderIndex) {
        long childrenCount = metaService.countBySql(ConditionsWrapper.builder().table(tableCode).eq("SY_PARENT", parentId));
        return parentTreeOrderIndex + String.format("%06d", childrenCount + 1);
    }

    private String generateTreeOrderIndexByOrderIndex(String tableCode, String parentId, String parentTreeOrderIndex, String orderIndex) {
        long childrenCount = metaService.countBySql(ConditionsWrapper.builder().table(tableCode).eq("SY_PARENT", parentId));
        if (!Strings.isNullOrEmpty(orderIndex) && Long.parseLong(orderIndex) != 0) {
            return parentTreeOrderIndex + String.format("%06d", Long.parseLong(orderIndex));
        }
        return parentTreeOrderIndex + String.format("%06d", childrenCount + 1);
    }

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public List<DynaBean> doSingleUpdateList(String tableCode, String updateStr, String funcType, String funcCode, String codeGenFieldInfo) {
        List<DynaBean> updateList = new ArrayList<>();
        List<DynaBean> lists = beanService.buildUpdateList(updateStr, tableCode);
        for (DynaBean bean : lists) {
            String action = bean.getStr("__action__");
            if ("doInsert".equals(action)) {
                //当前树形功能数据处理
                DynaBean parentBean;
                parentBean = metaService.selectOneByPk(tableCode, bean.getStr("SY_PARENT"), bean.getPkCode() + ",SY_PATH,SY_NODETYPE,SY_TREEORDERINDEX,SY_LAYER");
                //如果上级不是root节点，在父节点下添加节点的时候要把父节点类型改为GENERAL
                if (!NodeType.ROOT.equals(parentBean.getStr("SY_NODETYPE"))) {
                    parentBean.setStr("SY_NODETYPE", NodeType.GENERAL);
                    metaService.update(parentBean);
                }

                String mainId = bean.getStr(bean.getPkCode());
                bean.set("SY_PARENT", parentBean.getStr(bean.getPkCode()));
                bean.set("SY_PARENTPATH", parentBean.getStr("SY_PATH"));
                bean.set("SY_PATH", parentBean.getStr("SY_PATH") + "/" + mainId);
                bean.set("SY_NODETYPE", NodeType.LEAF);
                bean.set("SY_TREEORDERINDEX", generateTreeOrderIndexByOrderIndex(tableCode, parentBean.getStr(bean.getPkCode()), parentBean.getStr("SY_TREEORDERINDEX"), bean.getStr("SY_ORDERINDEX")));
                bean.set("SY_LAYER", parentBean.getInt("SY_LAYER") + 1);
                commonService.generateTreeOrderIndex(bean);
                commonService.buildModelCreateInfo(bean);
                if (StringUtil.isNotEmpty(codeGenFieldInfo)) {
                    commonService.buildCode(codeGenFieldInfo, bean);
                }
                //默认为启用数据
                bean.set("SY_STATUS", "1");
                metaService.insert(bean);
                bean.set(BeanService.KEY_TABLE_CODE, tableCode);
            } else {
                if (!commonService.validDynaBeanUpdatePerm(funcCode, bean.getTableCode(), bean.getPkCode(), bean.getPkValue())) {
                    throw new PlatformException("您没有此数据的更改权限！", PlatformExceptionEnum.UNKOWN_ERROR);
                }
                // 如果是修改的话并且修改的是排序字段，则同步修改树形排序字段值，新增的话如果新增的是排序字段
                if (null != bean.getStr("SY_ORDERINDEX") && !Strings.isNullOrEmpty(bean.getStr("SY_ORDERINDEX"))) {
                    String pKCode = bean.getStr(bean.getStr("$PK_CODE$"));
                    DynaBean dynaBean = metaService.selectOne(tableCode, ConditionsWrapper.builder().eq(bean.getStr("$PK_CODE$"), pKCode));
                    if (dynaBean != null) {
                        String nodetype = dynaBean.getStr("SY_NODETYPE");
                        String treeOrderIndex = dynaBean.getStr("SY_TREEORDERINDEX");
                        String newTreeOrderIndex = treeOrderIndex.substring(0, treeOrderIndex.length() - 6);
                        String format = String.format("%06d", Long.parseLong(bean.getStr("SY_ORDERINDEX")));
                        newTreeOrderIndex = newTreeOrderIndex + format;
                        //如果是普通节点，同步修改叶子节点的树形排序字段；如果是叶子节点只修改自己的树形排序字段
                        if (!Strings.isNullOrEmpty(nodetype) && NodeType.GENERAL.equals(nodetype)) {
                            //字典主键
                            String dictionaryId = dynaBean.getStr("DICTIONARYITEM_DICTIONARY_ID");
                            List<DynaBean> dynaBeanList = metaService.select(tableCode, ConditionsWrapper.builder().eq("DICTIONARYITEM_DICTIONARY_ID", dictionaryId).likeRight("SY_TREEORDERINDEX", treeOrderIndex));
                            if (dynaBeanList != null && dynaBeanList.size() > 0) {
                                for (DynaBean beans : dynaBeanList) {
                                    String syTreeorderindex = beans.getStr("SY_TREEORDERINDEX");
                                    String newSyTreeorderindex = syTreeorderindex.replaceAll(treeOrderIndex, newTreeOrderIndex);
                                    beans.setStr("SY_TREEORDERINDEX", newSyTreeorderindex);
                                    metaService.update(beans);
                                }
                            }
                        } else if (!Strings.isNullOrEmpty(nodetype) && NodeType.LEAF.equals(nodetype)) {
                            bean.setStr("SY_TREEORDERINDEX", newTreeOrderIndex);
                        }
                    }
                }
                commonService.buildModelModifyInfo(bean);
                metaService.update(bean);
                bean = metaService.selectOneByPk(tableCode, bean.getPkValue());
            }
            updateList.add(bean);
        }
        return updateList;
    }

    @Override
    public List<DynaBean> doMoreRootUpdateList(String tableCode, String updateStr, String funcType, String funcCode, String codeGenFieldInfo) {
        List<DynaBean> updateList = new ArrayList<>();
        List<DynaBean> lists = beanService.buildUpdateList(updateStr, tableCode);
        for (DynaBean bean : lists) {
            String action = bean.getStr("__action__");
            if ("doInsert".equals(action)) {
                //当前树形功能数据处理
                DynaBean parentBean = metaService.selectOneByPk(tableCode, bean.getStr("SY_PARENT"), bean.getPkCode() + ",SY_PATH,SY_NODETYPE,SY_TREEORDERINDEX,SY_LAYER");

                if (parentBean == null || NodeType.ROOT.equals(parentBean.getStr("SY_NODETYPE"))) {
                    String childForeignField = commonService.findSubFuncForeignField(funcCode);
                    parentBean = metaService.selectOne(tableCode, ConditionsWrapper.builder().eq(childForeignField, bean.getStr(childForeignField)).eq("SY_NODETYPE", "ROOT"));
                    if (parentBean == null) {
                        //添加多根树根节点
                        parentBean = commonService.addFuncMoreRootNode(funcCode, bean);
                    }
                } else {
                    //如果上级不是root节点，在父节点下添加节点的时候要把父节点类型改为GENERAL
                    parentBean.setStr("SY_NODETYPE", NodeType.GENERAL);
                    metaService.update(parentBean);
                }

                String mainId = bean.getStr(bean.getPkCode());
                bean.set("SY_PARENT", parentBean.getStr(bean.getPkCode()));
                bean.set("SY_PARENTPATH", parentBean.getStr("SY_PATH"));
                bean.set("SY_PATH", parentBean.getStr("SY_PATH") + "/" + mainId);
                bean.set("SY_NODETYPE", NodeType.LEAF);
                bean.set("SY_TREEORDERINDEX", generateTreeOrderIndexByOrderIndex(tableCode, parentBean.getStr(bean.getPkCode()), parentBean.getStr("SY_TREEORDERINDEX"), bean.getStr("SY_ORDERINDEX")));
                bean.set("SY_LAYER", parentBean.getInt("SY_LAYER") + 1);
                commonService.generateTreeOrderIndex(bean);
                commonService.buildModelCreateInfo(bean);
                if (StringUtil.isNotEmpty(codeGenFieldInfo)) {
                    commonService.buildCode(codeGenFieldInfo, bean);
                }
                //默认为启用数据
                bean.set("SY_STATUS", "1");
                metaService.insert(bean);
                bean.set(BeanService.KEY_TABLE_CODE, tableCode);
            } else {
                if (!commonService.validDynaBeanUpdatePerm(funcCode, bean.getTableCode(), bean.getPkCode(), bean.getPkValue())) {
                    throw new PlatformException("您没有此数据的更改权限！", PlatformExceptionEnum.UNKOWN_ERROR);
                }
                // 如果是修改的话并且修改的是排序字段，则同步修改树形排序字段值，新增的话如果新增的是排序字段
                if (null != bean.getStr("SY_ORDERINDEX") && !Strings.isNullOrEmpty(bean.getStr("SY_ORDERINDEX"))) {
                    String pKCode = bean.getStr(bean.getStr("$PK_CODE$"));
                    DynaBean dynaBean = metaService.selectOne(tableCode, ConditionsWrapper.builder().eq(bean.getStr("$PK_CODE$"), pKCode));
                    if (dynaBean != null) {
                        String nodetype = dynaBean.getStr("SY_NODETYPE");
                        String treeOrderIndex = dynaBean.getStr("SY_TREEORDERINDEX");
                        String newTreeOrderIndex = treeOrderIndex.substring(0, treeOrderIndex.length() - 6);
                        String format = String.format("%06d", Long.parseLong(bean.getStr("SY_ORDERINDEX")));
                        newTreeOrderIndex = newTreeOrderIndex + format;
                        //如果是普通节点，同步修改叶子节点的树形排序字段；如果是叶子节点只修改自己的树形排序字段
                        if (!Strings.isNullOrEmpty(nodetype) && NodeType.GENERAL.equals(nodetype)) {
                            //字典主键
                            String dictionaryId = dynaBean.getStr("DICTIONARYITEM_DICTIONARY_ID");
                            List<DynaBean> dynaBeanList = metaService.select(tableCode, ConditionsWrapper.builder().eq("DICTIONARYITEM_DICTIONARY_ID", dictionaryId).likeRight("SY_TREEORDERINDEX", treeOrderIndex));
                            if (dynaBeanList != null && dynaBeanList.size() > 0) {
                                for (DynaBean beans : dynaBeanList) {
                                    String syTreeorderindex = beans.getStr("SY_TREEORDERINDEX");
                                    String newSyTreeorderindex = syTreeorderindex.replaceAll(treeOrderIndex, newTreeOrderIndex);
                                    beans.setStr("SY_TREEORDERINDEX", newSyTreeorderindex);
                                    metaService.update(beans);
                                }
                            }
                        } else if (!Strings.isNullOrEmpty(nodetype) && NodeType.LEAF.equals(nodetype)) {
                            bean.setStr("SY_TREEORDERINDEX", newTreeOrderIndex);
                        }
                    }
                }
                commonService.buildModelModifyInfo(bean);
                metaService.update(bean);
                bean = metaService.selectOneByPk(tableCode, bean.getPkValue());
            }
            updateList.add(bean);
        }
        return updateList;
    }

    @Override
    public List<DynaBean> getTreeListBySearchName(String tableCode, String searchName, String ddCode) {
        List<DynaBean> resultList = new ArrayList<>();
        //查询树形功能数据
        if (Strings.isNullOrEmpty(ddCode)) {
            JSONTreeNode template = beanService.getTreeTemplate(tableCode);
            String textCode = template.getText();
            String id = template.getId();
            String code = template.getCode();
            String path = template.getNodePath();
            String parent = template.getParent();
            String text = template.getText();
            List<DynaBean> list = metaService.select(tableCode, ConditionsWrapper.builder().ne(textCode, "ROOT").like(textCode, searchName)
                    .selectColumns(String.format("%s,%s,%s,%s,%s", id, code, path, parent, text)));
            for (DynaBean dynaBean : list) {
                resultList.add(buildResultSearchTreeBean(dynaBean.getStr(id), dynaBean.getStr(code), dynaBean.getStr(text)
                        , dynaBean.getStr(path), dynaBean.getStr(parent)));
            }
            return resultList;
        } else {
            List<DynaBean> ddList = metaService.select("JE_CORE_DICTIONARY", ConditionsWrapper.builder().eq("DICTIONARY_DDCODE", ddCode));
            if (ddList.size() == 0) {
                return resultList;
            }
            DynaBean ddInfo = ddList.get(0);
            String ddId = ddInfo.getPkValue();
            List<DynaBean> list = metaService.select("JE_CORE_DICTIONARYITEM",
                    ConditionsWrapper.builder().eq("DICTIONARYITEM_DICTIONARY_ID", ddId)
                            .like("DICTIONARYITEM_ITEMNAME", searchName));
            for (DynaBean dicBean : list) {
                resultList.add(buildResultSearchTreeBean(dicBean.getStr("JE_CORE_DICTIONARYITEM_ID"),
                        dicBean.getStr("DICTIONARYITEM_ITEMCODE"), dicBean.getStr("DICTIONARYITEM_ITEMNAME"),
                        dicBean.getStr("SY_PATH"), dicBean.getStr("SY_PARENT")));
            }
            return resultList;
        }
    }

    private DynaBean buildResultSearchTreeBean(String id, String code, String text, String path, String parent) {
        DynaBean dynaBean = new DynaBean();
        dynaBean.setStr("ID", id);
        dynaBean.setStr("CODE", code);
        dynaBean.setStr("TEXT", text);
        dynaBean.setStr("PATH", path);
        dynaBean.setStr("PARENT", parent);
        return dynaBean;
    }

}
